package com.boot.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.entity.Dict;
import com.boot.entity.ImportantPersonInfoDTO;
import com.boot.entity.ImportantPersonRecord;
import com.boot.entity.ImportantPersonType;
import com.boot.mapper.pig.DictMapper;
import com.boot.mapper.pig.ImportantPersonRecordMapper;
import com.boot.mapper.pig.ImportantPersonTypeMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description: 重点人员缓存同步
 * @author: HuangX
 * @date: 2022/5/7
 */
@Component
@Slf4j
public class ImportantPersonAddTack {

    private static final int PAGE_SIZE = 5000;

    @Autowired
    private StringRedisTemplate redisTemplate;

//    @Autowired
//    private RedisTemplate redisTemplate;

    @Resource
    private ImportantPersonRecordMapper importantPersonRecordMapper;

    @Resource
    private ImportantPersonTypeMapper importantPersonTypeMapper;

    @Resource
    private DictMapper dictMapper;

    @NotNull
    private List<Dict> dictList;

    @NotNull
    private List<ImportantPersonType> typeList;

    /*
     * 每天00:30同步重点人员
     */
//    @Scheduled(cron = "0 0 3 * * ? ")
    public void runTask() throws Exception {
        TimeInterval timer = DateUtil.timer();
        //加锁，防止集群环境下的并发
        if (!redisTemplate.opsForValue().setIfAbsent("redis_lock_task", "-1", 7200, TimeUnit.SECONDS)) {
            return;
        }


        try {
            //清除已有缓存
//            redisTemplate.delete("ImportantPerson");


            log.debug("------------------------重点人员缓存同步开始--------------------------------");
            typeList = importantPersonTypeMapper.selectList(null);
            LambdaQueryWrapper<Dict> query = Wrappers.lambdaQuery();
            dictList = dictMapper.selectList(query.eq(Dict::getType, "checkType"));
            int total = importantPersonRecordMapper.selectCount(null);
//            int total = 100;
            if (total > PAGE_SIZE) {
                int loopSize = (int) Math.ceil(((double) total / PAGE_SIZE));
                for (int i = 1; i <= loopSize; i++) {
                    TimeInterval timer2 = DateUtil.timer();
                    doBiz(i);
                    log.info("执行第" + i + "次成功,用时:"+timer2.interval());
                }
            } else {
                doBiz(1);
            }

        } catch (Exception e) {
            log.error("ImportantPersonAddTack Exception ==>", e);
        } finally {
            redisTemplate.delete("redis_lock_task");
            log.debug("------------------------重点人员缓存同步开始--------------------------------");
        }

        log.info("=======重点人员同步总计执行时间=====:[{}]", timer.interval());
    }

    private void doBiz(int pageNum) {
        IPage<ImportantPersonRecord> page = new Page<>(pageNum, ImportantPersonAddTack.PAGE_SIZE);
//        List<ImportantPersonInfoDTO> result = importantPersonRecordMapper.getImportantByPage(page).getRecords();
        List<ImportantPersonRecord> result = importantPersonRecordMapper.selectPage(page, null).getRecords();
        List<ImportantPersonInfoDTO> list = new ArrayList<>();
        //数据组装,并发执行
        result.stream().parallel().forEachOrdered(item->{
            ImportantPersonInfoDTO dto = BeanUtil.toBean(item, ImportantPersonInfoDTO.class);
            ImportantPersonType type = typeList.stream().filter(a -> item.getPersonChildType().equals(a.getCode())).findFirst().get();
            Assert.notNull(type);

            Dict dict = dictList.stream().filter(a -> type.getType().equals(a.getCode())).findFirst().get();
            Assert.notNull(dict);

            dto.setPersonChildTypeName(type.getName());
            dto.setCountType(dict.getCode());
            dto.setCountTypeName(dict.getName());
            dto.setValidDay(type.getValidDay());
            list.add(dto);
        });

        //获取当前时间到0点间隔时间(秒)
        long seconds = DateUtil.between(new Date(), DateUtil.endOfDay(new Date()), DateUnit.SECOND);

        //redis批量执行
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
        redisTemplate.executePipelined((RedisCallback<String>) connection -> {
            list.forEach(item->{
                connection.set(Objects.requireNonNull(serializer.serialize("ImportantPerson:" + item.getCertNo() + "-" + item.getPersonChildType())),
                        Objects.requireNonNull(serializer.serialize(JSONObject.toJSONString(item))),
                        Expiration.seconds(60*5),
                        RedisStringCommands.SetOption.UPSERT);
            });
            return null;
        });
    }
}
